#include "spdlog/spdlog.h"
#include "json/json.h"

#include <boost/shared_ptr.hpp>
#include <memory>

#include "http_live_server.hpp"
#include "http_server_session.hpp"
#include "core/source_manager.hpp"
#include "core/media_source.hpp"
#include "httpflv_server_session.hpp"
// #include "httpflv_server_session.hpp"

using namespace mms;

HttpLiveServer::~HttpLiveServer()
{
}

bool HttpLiveServer::register_route()
{
    bool ret;
    ret = on_get("/api/stream_sink_count", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
        (void)req;
        (void)session;
        resp->add_header("Content-Type", "application/json");
        resp->add_header("Connection", "close");
        Json::Value root;
        root["code"] = 0;
        int count = 0;
        auto all_source = SourceManager::get_instance().get_sources();
        for(auto& v: all_source){
            count += (v.second->get_sinks_count());
        }
        root["count"] = count;
        
        // root["count"] = SourceManager::get_instance().get_source_count();
        std::string body = root.toStyledString();
        resp->add_header("Content-Length", std::to_string(body.size()));
        if (!(co_await resp->write_header(200, "OK"))) {
            resp->close();
            co_return;
        }

        bool ret = co_await resp->write_data((const uint8_t*)(body.data()), body.size());
        if (!ret) {
            resp->close();
            co_return;
        }
        resp->close();
        co_return;
        });
    if (!ret) {
        spdlog::error("register /api/streams_count failed");
        return false;
    }

    ret = on_get("/api/streams_count", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
        (void)req;
        (void)session;
        resp->add_header("Content-Type", "application/json");
        resp->add_header("Connection", "close");
        Json::Value root;
        root["code"] = 0;
        root["count"] = SourceManager::get_instance().get_source_count();
        std::string body = root.toStyledString();
        resp->add_header("Content-Length", std::to_string(body.size()));
        if (!(co_await resp->write_header(200, "OK"))) {
            resp->close();
            co_return;
        }

        bool ret = co_await resp->write_data((const uint8_t*)(body.data()), body.size());
        if (!ret) {
            resp->close();
            co_return;
        }
        resp->close();
        co_return;
        });
    if (!ret) {
        spdlog::error("register /api/streams_count failed");
        return false;
    }

    ret = on_get("/:app/:stream.abc", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
        (void)req;
        (void)session;
        resp->add_header("Content-Type", "application/json");
        resp->add_header("Connection", "close");
        Json::Value root;
        root["code"] = 0;
        root["app"] = req->get_path_param("app");
        root["stream"] = req->get_path_param("stream");
        std::string body = root.toStyledString();
        resp->add_header("Content-Length", std::to_string(body.size()));
        if (!(co_await resp->write_header(200, "OK"))) {
            resp->close();
            co_return;
        }

        bool ret = co_await resp->write_data((const uint8_t*)(body.data()), body.size());
        if (!ret) {
            resp->close();
            co_return;
        }
        resp->close();
        co_return;
        });

    if (!ret) {
        spdlog::error("register /:app/stream.abc failed");
        return false;
    }

    ret = on_get("/:app/:stream.flv", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
        (void)req;
        (void)session;
        auto http_flv_session = std::make_shared<HttpFlvServerSession>(req, resp);
        http_flv_session->service();
        // resp->add_header("Content-Type", "application/json");
        // resp->add_header("Connection", "close");
        // Json::Value root;
        // root["code"] = 0;
        // root["app"] = req->get_path_param("app");
        // root["stream"] = req->get_path_param("stream");
        // std::string body = root.toStyledString();
        // resp->add_header("Content-Length", std::to_string(body.size()));
        // if (!(co_await resp->write_header(200, "OK"))) {
        //     resp->close();
        //     co_return;
        // }

        // bool ret = co_await resp->write_data((const uint8_t*)(body.data()), body.size());
        // if (!ret) {
        //     resp->close();
        //     co_return;
        // }
        co_return;
        });

    if (!ret) {
        spdlog::error("register /:app/stream.abc failed");
        return false;
    }

    // ret = on_get("/:app/:stream.flv", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
    //     // 处理http-flv
    // });

    ret = on_post("/api/callback", [](std::shared_ptr<HttpServerSession<HttpConn>> session, std::shared_ptr<HttpRequest> req, std::shared_ptr<HttpResponse> resp)->boost::asio::awaitable<void> {
        // resp->add_header("Content-Type", "application/json");
        (void)req;
        (void)session;
        resp->add_header("Connection", "close");
        if (!(co_await resp->write_header(403, "forbidden"))) {
            resp->close();
            co_return;
        }

        co_return;
        });
    if (!ret) {
        spdlog::error("register /api/callback failed");
        return false;
    }

    return true;
}
